package cn.ug.activity.service.impl;

import cn.ug.activity.bean.SignInfoBean;
import cn.ug.activity.mapper.ActivitySignHistoryMapper;
import cn.ug.activity.mapper.ActivitySignMapper;
import cn.ug.activity.mapper.entity.ActivitySign;
import cn.ug.activity.mapper.entity.ActivitySignHistory;
import cn.ug.activity.service.SignService;
import cn.ug.bean.base.DataTable;
import cn.ug.bean.base.Order;
import cn.ug.bean.base.SerializeObject;
import cn.ug.bean.type.ResultType;
import cn.ug.config.RedisGlobalLock;
import cn.ug.core.SerializeObjectError;
import cn.ug.core.ensure.Ensure;
import cn.ug.enums.RateKeyEnum;
import cn.ug.enums.SharePrizeTypeEnum;
import cn.ug.feign.DrawPrizeService;
import cn.ug.feign.MemberAccountService;
import cn.ug.feign.RateSettingsService;
import cn.ug.mall.bean.GoldBeanProvideMarket;
import cn.ug.pay.bean.ProductOrderSummaryBean;
import cn.ug.pay.bean.response.MemberAccountBean;
import cn.ug.pay.bean.status.PayDistributePrefix;
import cn.ug.service.impl.BaseServiceImpl;
import cn.ug.util.DateUtils;
import cn.ug.util.UF;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.util.*;

@Service
public class SignServiceImpl extends BaseServiceImpl implements SignService {

    @Autowired
    private ActivitySignMapper activitySignMapper;

    @Autowired
    private ActivitySignHistoryMapper activitySignHistoryMapper;

    @Autowired
    private RateSettingsService rateSettingsService;

    @Autowired
    private MemberAccountService memberAccountService;

    @Resource
    private DrawPrizeService drawPrizeService;
    /**
     * 签到周期循环下标
     */
    private static final Integer SIGN_CYCLE = 6;

    private static Logger logger = LoggerFactory.getLogger(SignServiceImpl.class);
    @Resource
    private RedisGlobalLock redisGlobalLock;

    @Override
    public DataTable<ActivitySign> querySignList(int pageNum, int pageSize, String mobile, String name,
                                                 Integer totalSignMin, Integer totalSignMax, Integer totalGoldBeanMin,
                                                 Integer totalGoldBeanMax, Order order) {
        Page<ProductOrderSummaryBean> page = PageHelper.startPage(pageNum, pageSize);
        List<ActivitySign> activitySignList = activitySignMapper.querySignList(getParams(null, order.getOrder(), order.getSort())
                .put("mobile", mobile)
                .put("name", name)
                .put("totalSignMin", totalSignMin)
                .put("totalSignMax", totalSignMax)
                .put("totalGoldBeanMin", totalGoldBeanMin)
                .put("totalGoldBeanMax", totalGoldBeanMax)
                .toMap());
        return new DataTable<>(page.getPageNum(), page.getPageSize(), page.getTotal(), activitySignList);
    }

    @Override
    public DataTable<ActivitySignHistory> historyList(int pageNum, int pageSize, String mobile, String name, Order order) {
        Page<ProductOrderSummaryBean> page = PageHelper.startPage(pageNum, pageSize);
        List<ActivitySignHistory> activitySignHistoryList = activitySignHistoryMapper.queryByMobileAndName(getParams(null, order.getOrder(), order.getSort()).put("mobile", mobile)
                .put("name", name).toMap());
        return new DataTable<>(page.getPageNum(), page.getPageSize(), page.getTotal(), activitySignHistoryList);
    }

    @Override
    public SignInfoBean mySignInfo(String memberId) {
        SignInfoBean signInfoBean = new SignInfoBean();
        SerializeObject<MemberAccountBean> memberAccount = memberAccountService.findByMemberId(memberId);
        if (memberAccount != null && memberAccount.getData() != null) {
            MemberAccountBean memberAccountBean = memberAccount.getData();
            signInfoBean.setGoldBean(memberAccountBean.getUsableBean());
        }

        ActivitySign activitySign = activitySignMapper.queryByMemberId(memberId);
        if (activitySign != null) {
            String currentStr = DateUtils.getCurrentDateStr2();
            signInfoBean.setSignStatus(currentStr.compareTo(activitySign.getSignDate()) > 0 ? 0 : 1);
            signInfoBean.setTotalSign(activitySign.getTotalSign());

            //计算当前日期和签到日期相差天数
            int differentDay = dateCalculate(currentStr, activitySign.getSignDate());
            if (differentDay > 1) {
                signInfoBean.setTotalSign(0);
                //修改累计签到天数和连续签到天数
                ActivitySign params = new ActivitySign();
                params.setContinueSign(0);
                params.setTotalSign(0);
                params.setId(activitySign.getId());
                activitySignMapper.updateByPrimaryKeySelective(params);
                signInfoBean.setContinueSign(0);
                activitySign.setContinueSign(0);
            }
            resultExecute(differentDay, activitySign.getContinueSign(), signInfoBean);
        } else {
            signInfoBean.setSignStatus(0);
            signInfoBean.setTotalSign(0);
            signInfoBean.setContinueSign(0);
            //非1和0的值即可
            resultExecute(2, 0, signInfoBean);
        }
        return signInfoBean;
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public SerializeObject sign(String memberId) {
        String key = "sign:" + memberId;
        if (redisGlobalLock.lock(key)) {
            logger.info("----测试分布式锁-----memberId=" + memberId + "--------时间" + UF.getFormatDateTime(LocalDateTime.now()));
            try {
                Map resultMap = new HashMap();
                ActivitySign activitySign = activitySignMapper.queryByMemberId(memberId);
                //当前时间字符串
                String currentStr = DateUtils.getCurrentDateStr2();
                GoldBeanProvideMarket goldBeanProvideMarket = null;
                //签到第一天可获得金豆数量
                int oneDayGoldBean = 0;
                SerializeObject serializeObject = rateSettingsService.get(RateKeyEnum.GOLD_BEAN_PROVIDE_MARKET.getKey());
                if (serializeObject != null && serializeObject.getData() != null) {
                    goldBeanProvideMarket = JSON.parseObject(JSONObject.toJSONString(serializeObject.getData()), GoldBeanProvideMarket.class);
                    if (goldBeanProvideMarket.getSignType() == 2) {
                        oneDayGoldBean = goldBeanProvideMarket.getGoldBeanNum();
                    } else {
                        oneDayGoldBean = goldBeanProvideMarket.getSignDaysToGoldBeanList().get(0);
                    }
                }

                if (activitySign != null) {
                    if (currentStr.compareTo(activitySign.getSignDate()) == 0) {
                        //已签到 提示
                        return new SerializeObjectError("22000129");
                    }
                    //签到历史
                    ActivitySignHistory activitySignHistory = new ActivitySignHistory();
                    activitySignHistory.setGoldBean(oneDayGoldBean);

                    ActivitySign params = new ActivitySign();
                    params.setSignDate(currentStr);
                    params.setMemberId(memberId);
                    params.setId(activitySign.getId());

                    int differentDay = dateCalculate(currentStr, activitySign.getSignDate());
                    //连续签到
                    if (differentDay == 1) {
                        //7天一个循环 连续签到从第一天开始计数
                        if (activitySign.getContinueSign() == 7) {
                            params.setContinueSign(1);
                            params.setTotalGoldBean(activitySign.getTotalGoldBean() + oneDayGoldBean);
                            resultMap.put("goldBean", oneDayGoldBean);
                        } else {
                            params.setContinueSign(activitySign.getContinueSign() + 1);
                            //签到类型为每日签到金豆相同
                            if (goldBeanProvideMarket.getSignType() == 2) {
                                //第7天的时候
                                if (activitySign.getContinueSign() == 6) {
                                    params.setTotalGoldBean(activitySign.getTotalGoldBean() +
                                            goldBeanProvideMarket.getSignFullGoldBeanNum());
                                    resultMap.put("goldBean", goldBeanProvideMarket.getSignFullGoldBeanNum());
                                    activitySignHistory.setGoldBean(goldBeanProvideMarket.getSignFullGoldBeanNum());
                                } else {
                                    params.setTotalGoldBean(activitySign.getTotalGoldBean() +
                                            oneDayGoldBean);
                                    resultMap.put("goldBean", oneDayGoldBean);
                                    activitySignHistory.setGoldBean(oneDayGoldBean);
                                }
                            } else {
                                //每日签到金豆不同
                                params.setTotalGoldBean(activitySign.getTotalGoldBean() +
                                        goldBeanProvideMarket.getSignDaysToGoldBeanList().get(activitySign.getContinueSign()));
                                resultMap.put("goldBean", goldBeanProvideMarket.getSignDaysToGoldBeanList().get(activitySign.getContinueSign()));
                                activitySignHistory.setGoldBean(goldBeanProvideMarket.getSignDaysToGoldBeanList().get(activitySign.getContinueSign()));
                            }

                        }
                        params.setTotalSign(activitySign.getTotalSign() + 1);
                    } else {
                        //非连续签到 连续签到和累计签到从第一天开始计数
                        params.setContinueSign(1);
                        params.setTotalSign(1);
                        params.setTotalGoldBean(activitySign.getTotalGoldBean() + oneDayGoldBean);
                        resultMap.put("goldBean", oneDayGoldBean);
                    }
                    activitySignMapper.updateByPrimaryKeySelective(params);

                    activitySignHistory.setMemberId(memberId);
                    activitySignHistory.setSignDate(currentStr);
                    activitySignHistoryMapper.insert(activitySignHistory);
                    //签到金豆发放
                    memberAccountService.awardGiveOut(memberId, new BigDecimal(activitySignHistory.getGoldBean()), SharePrizeTypeEnum.GOLD_BEAN.getType());
                    //累计联系签到
                    resultMap.put("continueSign", params.getTotalSign());
                    //resultMap.put("totalSign", params.getTotalSign());
                    //连续签到7天额外奖励
                    if (params.getContinueSign() == 7 && goldBeanProvideMarket.getExtraAwardStatus() == 1) {
                        SerializeObject serializeObject1 = drawPrizeService.award(memberId);
                        Map result = (Map) serializeObject1.getData();
                        resultMap.putAll(result);
                    }
                    return new SerializeObject<>(ResultType.NORMAL, resultMap);
                }
                ActivitySign params = new ActivitySign();
                params.setSignDate(currentStr);
                params.setTotalGoldBean(oneDayGoldBean);
                params.setContinueSign(1);
                params.setTotalSign(1);
                params.setMemberId(memberId);
                activitySignMapper.insert(params);

                ActivitySignHistory activitySignHistory = new ActivitySignHistory();
                activitySignHistory.setMemberId(memberId);
                activitySignHistory.setSignDate(currentStr);
                activitySignHistory.setGoldBean(oneDayGoldBean);
                activitySignHistoryMapper.insert(activitySignHistory);
                //签到金豆发放
                memberAccountService.awardGiveOut(memberId, new BigDecimal(oneDayGoldBean), SharePrizeTypeEnum.GOLD_BEAN.getType());
                resultMap.put("continueSign", params.getTotalSign());
                resultMap.put("goldBean", oneDayGoldBean);
                return new SerializeObject<>(ResultType.NORMAL, resultMap);
            } catch (Exception e) {
                throw e;
            } finally {
                // 4、释放分布式锁 ================================================================
                redisGlobalLock.unlock(key);
            }
        } else {
            // 如果没有获取锁
            Ensure.that(true).isTrue("17000706");
        }
        return null;
    }

    /**
     * 时间计算
     *
     * @param currentStr
     * @param signDateStr
     * @return
     */
    private int dateCalculate(String currentStr, String signDateStr) {
        try {
            DateFormat df = new SimpleDateFormat("yyyy-MM-dd");
            //用户签到时间
            Date signDate = df.parse(signDateStr);
            //当前时间DATE
            Date currentDate = df.parse(currentStr);
            //计算是否连续签到
            int differentDay = DateUtils.differentDaysByMillisecond(signDate, currentDate);
            return differentDay;
        } catch (ParseException e) {
            e.printStackTrace();
        }
        return 0;
    }

    /**
     * @param differentDay     当前时间和签到时间相差天数
     * @param continueSignDays 连续签到天数
     * @param signInfoBean     查询返回结果集
     */
    private void resultExecute(int differentDay, int continueSignDays, SignInfoBean signInfoBean) {
        //查询配置
        SerializeObject serializeObject = rateSettingsService.get(RateKeyEnum.GOLD_BEAN_PROVIDE_MARKET.getKey());
        if (serializeObject != null && serializeObject.getData() != null) {
            GoldBeanProvideMarket goldBeanProvideMarket = JSON.parseObject(JSONObject.toJSONString(serializeObject.getData()), GoldBeanProvideMarket.class);
            if (goldBeanProvideMarket.getSignStatus() == 1) {
                List<SignInfoBean.SignDays> signDaysList = new ArrayList<>();
                Date statrDate = new Date();
                if (differentDay == 1 && continueSignDays != 7) {
                    statrDate = DateUtils.addDay(new Date(), -continueSignDays);
                } else if (differentDay == 0) {
                    statrDate = DateUtils.addDay(new Date(), -(continueSignDays - 1));
                }
                signInfoBean.setContinueSign(continueSignDays);

                if (goldBeanProvideMarket.getSignType() == 1) {
                    for (int i = 0; i < goldBeanProvideMarket.getSignDaysToGoldBeanList().size(); i++) {
                        SignInfoBean.SignDays signDay = new SignInfoBean.SignDays();
                        signDay.setDay(DateUtils.dateToStr(DateUtils.addDay(statrDate, i), "MM.dd"));
                        signDay.setGoldBean(goldBeanProvideMarket.getSignDaysToGoldBeanList().get(i));
                        if (i == SIGN_CYCLE && goldBeanProvideMarket.getExtraAwardStatus() == 1) {
                            signDay.setType(1);
                        } else {
                            signDay.setType(0);
                        }
                        signDaysList.add(signDay);
                    }
                }

                if (goldBeanProvideMarket.getSignType() == 2) {
                    for (int i = 0; i <= SIGN_CYCLE; i++) {
                        SignInfoBean.SignDays signDay = new SignInfoBean.SignDays();
                        signDay.setDay(DateUtils.dateToStr(DateUtils.addDay(statrDate, i), "MM.dd"));
                        if (i != SIGN_CYCLE) {
                            signDay.setGoldBean(goldBeanProvideMarket.getGoldBeanNum());
                            signDay.setType(0);
                        } else {
                            if (goldBeanProvideMarket.getExtraAwardStatus() == 1) {
                                signDay.setType(1);
                            } else {
                                signDay.setType(0);
                            }
                            signDay.setGoldBean(goldBeanProvideMarket.getSignFullGoldBeanNum());
                        }
                        signDaysList.add(signDay);
                    }
                }
                signInfoBean.setSignDaysList(signDaysList);
            }
        }
    }
}
